#include "swpsimactivitygraphicitem.h"

#include "../../documents/data/graphicdata.h"
#include "../../undo/basicitemcommands.h"
#include "../../utils/undomanager.h"
#include "graphicitemcommon.h"
#include "simmark.h"

using namespace core;
using namespace swp;

SwpSimActivityGraphicItem::SwpSimActivityGraphicItem(QGraphicsItem* parent) :
    SwpActivityGraphicItem(QString(), parent), ISimItem(),
    m_isInSimPath(false),
    m_originId(),
    m_origin(false),
    m_cost(),
    m_duration(),
    m_costMark(0),
    m_durationMark(0),
    m_added(false)
{
    setFlag(QGraphicsItem::ItemIsMovable, false);

    initProperties();
    initMarks();
}

SwpSimActivityGraphicItem::SwpSimActivityGraphicItem(
    SwpActivityGraphicItem* from,
    QGraphicsItem* parent) : SwpActivityGraphicItem(
        from->propertyValue("name").toString(), parent), ISimItem(),
        m_isInSimPath(false),
        m_originId(from->id()),
        m_origin(false),
        m_cost(),
        m_duration(),
        m_costMark(0),
        m_durationMark(0),
        m_added(false)
{
    setFlag(QGraphicsItem::ItemIsMovable, false);

    setPos(from->pos());

    setRectF(from->rect());

    initProperties();
    initMarks();
}

SwpSimActivityGraphicItem::~SwpSimActivityGraphicItem()
{
    if (scene() != 0)
    {
        scene()->removeItem(m_costMark);
        scene()->removeItem(m_durationMark);
    }

    delete m_costMark;
    delete m_durationMark;
}

bool SwpSimActivityGraphicItem::supportsConnection(
    const ConnectionData& connection) const
{
    return connection.ConnectionId == CONNECTION_SIM_PATH;
}

int SwpSimActivityGraphicItem::type() const
{
    return SWP_SIM_ACTIVITY_ITEM;
}

IEditorItem* SwpSimActivityGraphicItem::copy() const
{
    return new SwpSimActivityGraphicItem();
}

bool SwpSimActivityGraphicItem::isInSimPath() const
{
    return m_isInSimPath;
}

void SwpSimActivityGraphicItem::setInSimPath(bool in)
{
    if (in)
    {
        setPen(QPen(m_palette->acceptsConnectionColor(), 2));
    }
    else
    {
        setPen(QPen(m_palette->borderColor(), 1));
    }

    m_isInSimPath = in;
}

QUuid SwpSimActivityGraphicItem::originId() const
{
    return m_originId;
}

void SwpSimActivityGraphicItem::deserializationFinished(bool ok)
{
    SwpActivityGraphicItem::deserializationFinished(ok);

    repositionMarks();

    tryToAddMarks();

    m_originId = QUuid(m_origin.value().toString());
}

QList<Property> SwpSimActivityGraphicItem::properties() const
{
    QList<Property> ret;

    ret << m_origin << m_cost << m_duration
        << SwpActivityGraphicItem::properties();

    return ret;
}

QVariant SwpSimActivityGraphicItem::propertyValue(
    const QString& propertyName) const
{
    QVariant ret;

    if (propertyName == m_origin.Name)
    {
        ret = m_origin.value();
    }
    else if (propertyName == m_cost.Name)
    {
        ret = m_cost.value();
    }
    else if (propertyName == m_duration.Name)
    {
        ret = m_duration.value();
    }
    else
    {
        ret = SwpActivityGraphicItem::propertyValue(propertyName);
    }

    return ret;
}

void SwpSimActivityGraphicItem::propertyChanged(const QString& property,
    const QVariant& newValue, bool silent)
{
    bool changed = false;
    bool skip = false;

    if (property == m_origin.Name && m_origin.value() != newValue)
    {
        if (!silent)
        {
            PropertyChangeCommand* command = new PropertyChangeCommand(
                this, m_cost, newValue);

            UndoManager::getInstance()->push(
                dynamic_cast<IDocumentData*>(scene()), command);
        }

        m_origin.setValue(newValue);

        if (silent && isSelected()) {
            setSelected(false);
            setSelected(true);
        }

        changed = true;
    }
    else if (property == m_cost.Name && m_cost.value() != newValue)
    {
        if (!silent)
        {
            PropertyChangeCommand* command = new PropertyChangeCommand(
                this, m_cost, newValue);

            UndoManager::getInstance()->push(
                dynamic_cast<IDocumentData*>(scene()), command);
        }

        m_cost.setValue(newValue);

        if (silent)
        {
            m_costMark->setText(newValue.toString());
            repositionMarks();
        }

        if (silent && isSelected()) {
            setSelected(false);
            setSelected(true);
        }

        changed = true;
    }
    else if (property == m_duration.Name && m_duration.value() != newValue)
    {
        if (!silent)
        {
            PropertyChangeCommand* command = new PropertyChangeCommand(
                this, m_duration, newValue);

            UndoManager::getInstance()->push(
                dynamic_cast<IDocumentData*>(scene()), command);
        }

        m_duration.setValue(newValue);

        if (silent)
        {
            m_durationMark->setText(newValue.toString());
            repositionMarks();
        }

        if (silent && isSelected()) {
            setSelected(false);
            setSelected(true);
        }

        changed = true;
    }
    else
    {
        bool found = false;

        const QList<Property> props = SwpActivityGraphicItem::properties();

        foreach (const Property& prop, props)
        {
            if (prop.Name == property)
            {
                found = true;
                break;
            }
        }

        if (found)
        {
            skip = true;
            SwpActivityGraphicItem::propertyChanged(property, newValue,
                silent);
        }
    }

    if (!skip)
    {
        if (silent && changed)
        {
            GraphicData* data = dynamic_cast<GraphicData*>(m_documentData);

            Q_ASSERT(data != 0); // shouldn't be null

            data->emitDataChanged();
        }
    }
}

QVariantList SwpSimActivityGraphicItem::optionList(
    const QString& propertyName) const
{
    QVariantList ret;

    return ret;
}

QVariantList SwpSimActivityGraphicItem::autocomplete(
    const QString& propertyName) const
{
    QVariantList ret;

    return ret;
}

void SwpSimActivityGraphicItem::repositionMarks()
{
    const QRectF pRect = boundingRect();
    QRectF rect = m_costMark->boundingRect();

    const QPointF _scenePos = pos();

    m_costMark->setPos(_scenePos.x() + (pRect.width() - rect.width()) / 2,
        _scenePos.y() -(rect.width() / 2));

    rect = m_durationMark->boundingRect();

    m_durationMark->setPos(_scenePos.x() + (pRect.width() - rect.width()) / 2,
        _scenePos.y() + pRect.height() - (rect.width() / 2));
}

QVariant SwpSimActivityGraphicItem::itemChange(GraphicsItemChange change,
    const QVariant &value)
{
    if (change == QGraphicsItem::ItemSceneHasChanged)
    {
        tryToAddMarks();
    }

    return SwpActivityGraphicItem::itemChange(change, value);
}

void SwpSimActivityGraphicItem::initProperties()
{
    m_origin.Name = "origin";
    m_origin.Text = QObject::tr("Origin");
    m_origin.setValue(QVariant(m_originId.toString()));

    m_cost.Name = "cost";
    m_cost.Text = QObject::tr("Cost");
    m_cost.setValue(QVariant(0));

    m_duration.Name = "duration";
    m_duration.Text = QObject::tr("Duration");
    m_duration.setValue(QVariant(0));

    m_nameProp.setVisibleToEditor(false);
    m_inputProp.setVisibleToEditor(false);
    m_outputProp.setVisibleToEditor(false);
    m_actionsProp.setVisibleToEditor(false);
}

void SwpSimActivityGraphicItem::initMarks()
{
    m_costMark = new SimMark(30, SimMark::Cost, m_cost.value().toString());
    m_costMark->setZValue(SIM_MARK_ZVALUE);

    m_durationMark = new SimMark(30, SimMark::Duration,
        m_duration.value().toString());
    m_durationMark->setZValue(SIM_MARK_ZVALUE);

    repositionMarks();
    tryToAddMarks();
}

void SwpSimActivityGraphicItem::tryToAddMarks()
{
    if (scene() != 0 && !m_added)
    {
        m_added = true;
        scene()->addItem(m_costMark);
        scene()->addItem(m_durationMark);
    }
}
